﻿using System.Windows;
namespace Super.Admin.Utils.EventAggregator
{
    public class EventAggregator : IEventAggregator
    {
        private static EventAggregator _default = new EventAggregator();
        public static EventAggregator Default => _default;
        private readonly object _lock = new object();
        private readonly Dictionary<Type, List<Subscription>> _subscriptions = new Dictionary<Type, List<Subscription>>();  // 事件类型到订阅列表的映射
        private readonly Dictionary<Guid, Subscription> _tokens = new Dictionary<Guid, Subscription>(); // 令牌到订阅的映射
        /// <summary>
        /// 订阅事件
        /// </summary>
        /// <typeparam name="TEvent"></typeparam>
        /// <param name="handler"></param>
        /// <returns></returns>
        public SubscriptionToken Subscribe<TEvent>(Action<TEvent> handler) where TEvent : class
        {
            return Subscribe<TEvent>(handler, null, false, null);
        }
        /// <summary>
        /// 订阅带过滤条件的事件
        /// </summary>
        /// <typeparam name="TEvent"></typeparam>
        /// <param name="handler"></param>
        /// <param name="filter"></param>
        /// <returns></returns>
        public SubscriptionToken Subscribe<TEvent>(Action<TEvent> handler, Predicate<TEvent> filter) where TEvent : class
        {
            Predicate<object> objectFilter = filter != null ? e => filter((TEvent)e) : (Predicate<object>)null;
            return Subscribe<TEvent>(handler, objectFilter, false, null);
        }
        /// <summary>
        /// 订阅带执行选项的事件
        /// </summary>
        /// <typeparam name="TEvent"></typeparam>
        /// <param name="handler"></param>
        /// <param name="keepSubscriberReferenceAlive"></param>
        /// <param name="dispatcherPriority"></param>
        /// <returns></returns>
        public SubscriptionToken Subscribe<TEvent>(Action<TEvent> handler, bool keepSubscriberReferenceAlive = false, Control invokeControl = null) where TEvent : class
        {
            return Subscribe<TEvent>(handler, null, keepSubscriberReferenceAlive, invokeControl);
        }
        /// <summary>
        /// 核心订阅方法
        /// </summary>
        /// <typeparam name="TEvent"></typeparam>
        /// <param name="handler"></param>
        /// <param name="filter"></param>
        /// <param name="keepSubscriberReferenceAlive"></param>
        /// <param name="dispatcherPriority"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        private SubscriptionToken Subscribe<TEvent>(Action<TEvent> handler, Predicate<object> filter, bool keepSubscriberReferenceAlive, Control invokeControl) where TEvent : class
        {
            if (handler == null) throw new ArgumentNullException(nameof(handler));
            var eventType = typeof(TEvent);
            var subscription = new Subscription(eventType, handler, filter, keepSubscriberReferenceAlive, invokeControl, handler.Target);
            lock (_lock)
            {
                if (!_subscriptions.TryGetValue(eventType, out var eventSubscriptions))
                {
                    eventSubscriptions = new List<Subscription>();
                    _subscriptions[eventType] = eventSubscriptions;
                }
                eventSubscriptions.Add(subscription);
                var token = new SubscriptionToken(eventType);
                _tokens[token.Id] = subscription;
                return token;
            }
        }
        /// <summary>
        /// 取消订阅
        /// </summary>
        /// <typeparam name="TEvent"></typeparam>
        /// <param name="token"></param>
        /// <exception cref="ArgumentNullException"></exception>
        public void Unsubscribe<TEvent>(SubscriptionToken token) where TEvent : class
        {
            if (token == null) throw new ArgumentNullException(nameof(token));
            lock (_lock)
            {
                if (_tokens.TryGetValue(token.Id, out var subscription))
                {
                    if (_subscriptions.TryGetValue(token.EventType, out var eventSubscriptions))
                    {
                        eventSubscriptions.Remove(subscription);
                        if (eventSubscriptions.Count == 0)
                        {
                            _subscriptions.Remove(token.EventType);
                        }
                    }
                    _tokens.Remove(token.Id);
                }
            }
        }
        /// <summary>
        /// 取消所有订阅
        /// </summary>
        public void UnsubscribeAll()
        {
            lock (_lock)
            {
                _subscriptions.Clear();
                _tokens.Clear();
            }
        }
        /// <summary>
        /// 发布事件
        /// </summary>
        /// <typeparam name="TEvent"></typeparam>
        /// <param name="event"></param>
        public void Publish<TEvent>(TEvent @event) where TEvent : class
        {
            Publish(@event, true);
        }
        /// <summary>
        /// 发布事件并指定是否在UI线程执行
        /// </summary>
        /// <typeparam name="TEvent"></typeparam>
        /// <param name="event"></param>
        /// <param name="executeOnUIThread"></param>
        /// <exception cref="ArgumentNullException"></exception>
        public void Publish<TEvent>(TEvent @event, bool executeOnUIThread) where TEvent : class
        {
            if (@event == null) throw new ArgumentNullException(nameof(@event));
            List<Subscription> toExecute;
            Type eventType = typeof(TEvent);
            lock (_lock)
            {
                if (!_subscriptions.TryGetValue(eventType, out var eventSubscriptions)) return;
                // 收集符合条件的订阅
                toExecute = eventSubscriptions.Where(s => s.Filter == null || s.Filter(@event)).ToList();
            }

            // 在锁外执行处理程序
            foreach (var subscription in toExecute)
            {
                // 检查订阅者是否已被垃圾回收
                if (subscription.SubscriberReference != null && !subscription.SubscriberReference.IsAlive && !subscription.KeepSubscriberReferenceAlive)
                {
                    // 自动清理无效订阅
                    UnsubscribeBySubscription(subscription);
                    continue;
                }
                // 执行处理程序
                if (executeOnUIThread && subscription.InvokeControl != null && subscription.InvokeControl.InvokeRequired)
                {
                    subscription.InvokeControl.Invoke(new Action(() =>
                    {
                        subscription.Handler.DynamicInvoke(@event);
                    }));
                }
                else
                {
                    subscription.Handler.DynamicInvoke(@event);
                }
            }
        }
        /// <summary>
        /// 内部方法：通过订阅信息取消订阅
        /// </summary>
        /// <param name="subscription"></param>
        private void UnsubscribeBySubscription(Subscription subscription)
        {
            lock (_lock)
            {
                if (_subscriptions.TryGetValue(subscription.EventType, out var eventSubscriptions))
                {
                    eventSubscriptions.Remove(subscription);
                    if (eventSubscriptions.Count == 0)
                    {
                        _subscriptions.Remove(subscription.EventType);
                    }
                }
                // 从令牌字典中移除
                var token = _tokens.FirstOrDefault(kvp => kvp.Value == subscription);
                if (token.Value != null)
                {
                    _tokens.Remove(token.Key);
                }
            }
        }
        /// <summary>
        /// 内部方法：通过令牌取消订阅
        /// </summary>
        /// <param name="token"></param>
        internal void Unsubscribe(SubscriptionToken token)
        {
            if (token == null) return;

            lock (_lock)
            {
                if (_tokens.TryGetValue(token.Id, out var subscription))
                {
                    UnsubscribeBySubscription(subscription);
                }
            }
        }
    }
}
